#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <list>
#include <string>
#include <stack>

#include <util.h>
#include <timer.h>

class Matriz {
	public:
		Matriz( int w = 0, int h = 0 ) : _m(0) { reset( w, h ); }
		~Matriz() { delete [] _m; }

		void reset( int w, int h ) {
			delete [] _m;
			_m = 0;
			_w = 0;
			_h = 0;

			if ( w < 1 || h < 1 ) return;

			_w = w;
			_h = h;
			_m = new int [ w * h ];
		}

		int width() const { return _w; }
		int height() const { return _h; }
		
		int *operator[] ( int fila ) { return _m + fila * _w; }
		int &operator()( int fila, int columna ) { return _m[ fila * _w + columna ]; }
		int operator()( int fila, int columna ) const { return _m[ fila * _w + columna ]; }

		bool candidato( int fila, int columna ) const { return (*this)(fila, columna) % 2 == 0; }

		int _w, _h, *_m;
};

using namespace std;

extern int resolver( const Matriz &petalos );

/** Acá empieza el generador. **/
static int gMin = 1;
static int gMax = 1000;

// 1 sola fila
void generarMejorCaso( ostream &salida ) {
	int total = gMax * gMax;
	Timer t;

	for ( int w = 1; w <= total; w++ ) {
		Matriz m( w, 1 );
		for ( int i = 0; i < w; i++ )
			m._m[i] = 2;

		t.comenzar();
		volatile int res = resolver( m );
		t.terminar();

		salida << w << '\t' <<  t.getTiempo() << '\n';
	}
}

// w*h con todos los pétalos impares
void generarPeorCaso( ostream &salida ) {
	Timer t;
	int total = gMax * gMax;
	int w = 1;

	for ( int h = 1; h <= total; h++ ) {
		Matriz m( w, h );
		int total = w * h;
		for ( int i = 0; i < total; i++ )
			m._m[i] = 7;

		t.comenzar();
		volatile int res = resolver( m );
		t.terminar();

		salida << w*h << '\t' << t.getTiempo() << '\n';
	}
}

void generarCasosAleatorios( ostream &salida ) {
	Timer t;

	for ( int tamano = 1; tamano < gMax*gMax; tamano++ ) {
		int w = 1 + rand() % tamano;
		int h = tamano / w;

		Matriz m( w, h );
		for ( int i = 0; i < w*h; i++ ) {
			m._m[i] = 1 + rand() % 9;
		}

		t.comenzar();
		volatile int res = resolver( m );
		t.terminar();

		salida << w*h << '\t' << t.getTiempo() << '\n';

	}
}

bool establecerMaximo( const char *str ) {
	if ( !str2int( str, &gMax ) ) {
		cerr << "Máximo no reconocido, debe ser un número entero.\n";
		return false;
	}
	return true;
}

bool establecerMinimo( const char *str ) {
	if ( !str2int( str, &gMin ) ) {
		cerr << "Mínimo no reconocido, debe ser un número entero.\n";
		return false;
	}
	return true;
}
